package com.bsj.pay.service.impl;

import com.bsj.pay.common.Result;
import com.bsj.pay.config.GlobalConfig;
import com.bsj.pay.dao.AreaDao;
import com.bsj.pay.dao.ChargeAccountDao;
import com.bsj.pay.dao.OrderDao;
import com.bsj.pay.dao.PartnerDao;
import com.bsj.pay.model.AccountBean;
import com.bsj.pay.model.AreaBean;
import com.bsj.pay.model.ChargeAccountBean;
import com.bsj.pay.model.PartnerBean;
import com.bsj.pay.service.AccountService;
import com.bsj.pay.service.ChargeAccountService;
import com.bsj.pay.util.HttpUtil;
import com.bsj.pay.util.SpringUtil;
import com.bsj.pay.util.ThreadPoolUtils;
import com.bsj.pay.util.json.JSONUtil;
import com.bsj.pay.util.platform.PlatformInterface;
import com.bsj.pay.util.security.MD5;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ChargeAccountServiceImpl implements ChargeAccountService {

    private static final Logger logger = LogManager.getLogger(ChargeAccountServiceImpl.class);

    @Autowired
    private ChargeAccountDao dao;

    @Autowired
    private PartnerDao partnerDao;

    @Autowired
    private AreaDao areaDao;

    @Autowired
    private AccountService accountService;

    @Autowired
    private OrderDao orderDao;

    @Override
    public long insert(ChargeAccountBean t) {
        // TODO Auto-generated method stub
        return dao.insert(t);
    }

    @Override
    public int deleteById(Long id) {
        // TODO Auto-generated method stub
        return dao.deleteById(id);
    }

    @Override
    public List<ChargeAccountBean> queryList(ChargeAccountBean t) {
        // TODO Auto-generated method stub
        return dao.queryList(t);
    }

    @Override
    public int update(ChargeAccountBean t) {
        // TODO Auto-generated method stub
        return dao.update(t);
    }

    @Override
    public ChargeAccountBean getById(Long Id) {
        // TODO Auto-generated method stub
        return dao.getById(Id);
    }

    @Override
    public long count(ChargeAccountBean t) {
        // TODO Auto-generated method stub
        return dao.count(t);
    }

    @Override
    public PageInfo<ChargeAccountBean> pageList(ChargeAccountBean t, int pageNum, int pageSize) {
        // TODO Auto-generated method stub
        PageHelper.startPage(pageNum, pageSize);
        List<ChargeAccountBean> list = dao.queryList(t);
        PageInfo<ChargeAccountBean> pageInfo = new PageInfo<ChargeAccountBean>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<ChargeAccountBean> pageDayFinanceList(ChargeAccountBean t, int pageNum, int pageSize) {
        // TODO Auto-generated method stub
        PageHelper.startPage(pageNum, pageSize);
        List<ChargeAccountBean> list = dao.queryDayFinanceList(t);
        PageInfo<ChargeAccountBean> pageInfo = new PageInfo<ChargeAccountBean>(list);
        return pageInfo;
    }

    @Override
    public int removeById(Long id) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public List<ChargeAccountBean> queryAll() {
        // TODO Auto-generated method stub
        return null;
    }


    @Override
    public int removeByTime(long startTime, long endTime) {
        // TODO Auto-generated method stub
        return dao.removeByTime(startTime, endTime);
    }

    @Override
    public Result receiveOrder(ChargeAccountBean insertModel) {
        // TODO Auto-generated method stub\
        Result result = new Result();
        AreaBean phoneArea = new AreaBean();
        phoneArea.setArea(insertModel.getArea());
        List<AreaBean> areaList = areaDao.queryList(phoneArea);
        if (areaList == null || areaList.size() == 0) {
            logger.info("不支持的缴费地区");
            result.setCode(201);
            result.setMsg("不支持的缴费地区");
            result.setData("");
            return result;
        }
        insertModel.setArea_code(areaList.get(0).getArea_code());

        ChargeAccountBean queryModel = new ChargeAccountBean();
        queryModel.setPartner_id(insertModel.getPartner_id());
        queryModel.setPartner_order_no(insertModel.getPartner_order_no());
        if (dao.count(queryModel) > 0) {
            logger.info("订单号已存在");
            result.setCode(202);
            result.setMsg("订单号已存在");
            result.setData("");
            return result;
        }

        if (dao.failChargeCount(insertModel.getPartner_id(), insertModel.getAccount()) > 0) {
            logger.info("此户号充值错误次数过多");
            result.setCode(203);
            result.setMsg("此户号充值错误次数过多");
            result.setData("");
            return result;
        }

        insertModel.setStatus(-1);
        insertModel.setCreate_time(System.currentTimeMillis() / 1000);
        insertModel.setUpdate_time(insertModel.getCreate_time());
        dao.insert(insertModel);

        result.setCode(1);
        result.setMsg("数据收录成功");
        result.setData("");
        logger.info("数据收录成功,订单号:" + insertModel.getPartner_order_no());
        OrderServiceImpl.lastActiveTime = System.currentTimeMillis() / 1000;
        return result;
    }

    @Override
    public void PartnerNotifyTask() throws Exception {
        // TODO Auto-generated method stub
        List<ChargeAccountBean> notNotifyList = dao.getNeedNotifyList(GlobalConfig.query_time_out);
        for (ChargeAccountBean chargeAccount : notNotifyList) {
            this.partnerNotify(chargeAccount.getId());
        }
    }

    @Override
    @Transactional
    public boolean partnerNotify(Long chargeAccountId) throws Exception {
        ChargeAccountBean chargeAccount = dao.getById(chargeAccountId);
        if (chargeAccount == null) {
            logger.info("没有找到对应充值对单:" + chargeAccountId);
            throw new Exception("没有找到对应充值对单:" + chargeAccountId);
        }
        if (chargeAccount.getNotify_status() == 1) {
            logger.info("已回调，不处理");
            throw new Exception("已回调，不处理");
        }
        if (StringUtils.isEmpty(chargeAccount.getNotify_url())) {
            logger.info("该订单无回调地址:" + chargeAccountId);
            throw new Exception("该订单无回调地址");
        }
        ChargeAccountBean updatechargeAccount = new ChargeAccountBean();
        updatechargeAccount.setId(chargeAccount.getId());
        updatechargeAccount.setNotify_times(chargeAccount.getNotify_times() + 1);
        dao.update(updatechargeAccount);
        PartnerBean partner = partnerDao.getById(chargeAccount.getPartner_id());
        List<String> officialOrderNo = orderDao.queryOfficialOrderNoList(chargeAccount.getId());
        new Thread(new Runnable() {
            public void run() {
                try {
                    Map<String, String> params = new HashMap<String, String>();
                    params.put("status", String.valueOf(chargeAccount.getCharge_status()));
                    params.put("partner_id", String.valueOf(chargeAccount.getPartner_id()));
                    params.put("partner_order_no", chargeAccount.getPartner_order_no());
                    params.put("account", chargeAccount.getAccount());
                    params.put("amount", String.valueOf(chargeAccount.getAmount()));
                    int charge_amount = dao.getChargeSuccAmountById(chargeAccount.getId());
                    params.put("charge_amount", String.valueOf(charge_amount));
                    params.put("type", String.valueOf(chargeAccount.getType()));
                    params.put("official_order_no", JSONUtil.toJson(officialOrderNo));
                    params.put("remarks", StringUtils.isEmpty(chargeAccount.getRemarks()) ? "" : chargeAccount.getRemarks());
                    String md5 = MD5.getMD5(params.get("status") + params.get("partner_id") + params.get("partner_order_no")
                            + params.get("account") + params.get("amount") + params.get("charge_amount") + params.get("type") + partner.getApi_key());
                    params.put("sign", md5);
                    String body = HttpUtil.post(chargeAccount.getNotify_url(), params);
                    logger.info("回调给合作商,订单号:{},状态{},结果:{}", chargeAccount.getId(), chargeAccount.getCharge_status(), body);
                    if (StringUtils.isEmpty(body)) {
                        return;
                    }
                    body = body.replaceAll("\r|\n", "").trim();
                    if ("SUCCESS".equals(body) || "success".equals(body)) {
                        ChargeAccountBean localchargeAccount = new ChargeAccountBean();
                        localchargeAccount.setId(chargeAccount.getId());
                        localchargeAccount.setNotify_status(1);
                        localchargeAccount.setNotify_time(System.currentTimeMillis() / 1000);
                        dao.update(localchargeAccount);
                        logger.info("###################回调给合作商成功,订单号:{},充值状态{}###################", chargeAccount.getId(), chargeAccount.getCharge_status());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.info("回调给合作商,出现异常,订单号:{}", chargeAccount.getId());
                }
            }
        }).start();
        return true;
    }

    @Override
    public void procesSuccOrder(Long id) {
        // TODO Auto-generated method stub
        ChargeAccountBean chargeAccount = dao.getById(id);
        int succAmount = dao.getChargeSuccAmountById(id);
        ChargeAccountBean updatechargeAccount = new ChargeAccountBean();
        updatechargeAccount.setId(id);
        if (succAmount >= chargeAccount.getAmount()) {
            updatechargeAccount.setStatus(2);
            updatechargeAccount.setCharge_status(2);
        } else {
            updatechargeAccount.setStatus(1);
            updatechargeAccount.setCharge_status(1);
        }
        updatechargeAccount.setUpdate_time(System.currentTimeMillis() / 1000);
        dao.update(updatechargeAccount);
    }

	/*@Override
	public List<ChargeAccountBean> getLeftCount() {
		// TODO Auto-generated method stub
		return dao.getLeftCount(GlobalConfig.charge_time_out);
	}
	
	@Override
	public ChargeAccountBean getLeftCountByAmount(int amount) {
		// TODO Auto-generated method stub
		return dao.getLeftCountByAmount(GlobalConfig.charge_time_out,amount);
	}*/

    @Override
    public double sumMoney(ChargeAccountBean chargeAccount) {
        // TODO Auto-generated method stub
        return dao.sumMoney(chargeAccount);
    }

    @Override
    public List<ChargeAccountBean> queryDayList(ChargeAccountBean chargeAccount) {
        // TODO Auto-generated method stub
        return dao.queryDayList(chargeAccount);
    }

    @Override
    public int batchFailByPartnerId(Long partnerId) {
        // TODO Auto-generated method stub
        return dao.batchFailByPartnerId(partnerId, GlobalConfig.query_time_out);
    }

    @Override
    public long failChargeCount(Long partnerId, String account) {
        // TODO Auto-generated method stub
        return dao.failChargeCount(partnerId, account);
    }

    @Override
    public int getLeftAmount() {
        // TODO Auto-generated method stub
        return dao.getLeftAmount();
    }

    @Override
    public void CheckChargeAccountTask() throws Exception {
        // TODO Auto-generated method stub
        ChargeAccountBean queryModel = new ChargeAccountBean();
        queryModel.setStatus(-1);
        List<ChargeAccountBean> needCheckChargeAccountList = this.dao.queryList(queryModel);
        if (needCheckChargeAccountList == null || needCheckChargeAccountList.size() == 0) return;
        String operator = "wsgw";
        if (GlobalConfig.operator == 2) operator = "cloud";
        for (ChargeAccountBean chargeAccount : needCheckChargeAccountList) {
            if (chargeAccount.getOperator() != null) {
                operator = chargeAccount.getOperator();
            }
            AccountBean account = accountService.getOneCanQuery(operator);
            if (account == null) {
                break;
            } else {
                try {
                    accountService.updateAccountProxy(account);
                    AccountBean updateAccount = new AccountBean();
                    updateAccount.setId(account.getId());
                    updateAccount.setBind_last_time(System.currentTimeMillis() / 1000);
                    accountService.update(updateAccount);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    break;
                }
            }
            ThreadPoolUtils.getCheckChargeAccountPool().execute(() -> {
                logger.info("开启检测充值账号子线程,账号ID:{}", chargeAccount.getId());
                this.checkChargeAccount(account, chargeAccount);
                logger.info("检测充值账号子线程已结束！");
            });
        }
        do {
            Thread.sleep(1000);
        } while (ThreadPoolUtils.getCheckChargeAccountPool().getActiveCount() != 0);
    }

    @Override
    public void checkChargeAccount(AccountBean account, ChargeAccountBean chargeAccount) {
        // TODO Auto-generated method stub
        String operator = "wsgw";
        if (GlobalConfig.operator == 2) operator = "cloud";
        PlatformInterface inf = (PlatformInterface) SpringUtil.getBean(operator + "Util");
        inf.checkChargeAccount(chargeAccount, account);
    }

    @Override
    public int getChargeSuccAmountById(Long charge_account_id) {
        // TODO Auto-generated method stub
        return dao.getChargeSuccAmountById(charge_account_id);
    }

    @Override
    public int addBindFailCount(Long id) {
        // TODO Auto-generated method stub
        return dao.addBindFailCount(id);
    }

}
